package top.milkbox.sys.modular.user.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import top.milkbox.common.enums.CommonSortTypeEnum;
import top.milkbox.common.exceprion.CommonServiceException;
import top.milkbox.common.service.impl.CommonServiceImpl;
import top.milkbox.sys.modular.permission.service.SysPermissionService;
import top.milkbox.sys.modular.user.entity.SysUserEntity;
import top.milkbox.sys.modular.user.enums.SysUserGenderEnum;
import top.milkbox.sys.modular.user.enums.SysUserStatusEnum;
import top.milkbox.sys.modular.user.mapStruct.SysUserMapStruct;
import top.milkbox.sys.modular.user.mapper.SysUserMapper;
import top.milkbox.sys.modular.user.param.*;
import top.milkbox.sys.modular.user.service.SysUserService;
import top.milkbox.sys.modular.user.vo.SysUserVo;
import top.milkbox.common.utils.CommonUtil;

import java.util.List;

/**
 * 系统_用户表（sys_user）服务层实现类
 *
 * @author milkbox
 * @date 2024-1-23
 */
@Slf4j
@Service
public class SysUserServiceImpl extends CommonServiceImpl<SysUserMapper, SysUserEntity> implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Lazy
    @Autowired
    private SysPermissionService sysPermissionService;

    @Autowired
    private SysUserMapStruct sysUserMapStruct;

    public static final int LOG_ROUNDS = 12; // 加密程度，数值越高越安全越慢

    @Override
    public void add(SysUserAddParam addParam) {
        SysUserEntity entity = sysUserMapStruct.addParamToEntity(addParam);
        super.save(entity);
    }

    @Override
    public void delete(List<SysUserIdParam> paramList) {
        super.removeByIds(paramList.stream().map(SysUserIdParam::getId).toList());
    }

    @Override
    public void edit(SysUserEditParam editParam) {
        findEntity(editParam.getId());
        SysUserEntity entity = sysUserMapStruct.editParamToEntity(editParam);
        super.updateById(entity);
    }

    @Override
    public SysUserVo detail(SysUserIdParam idParam) {
        SysUserEntity entity = findEntity(idParam.getId());
        SysUserVo vo = sysUserMapStruct.entityToVo(entity);
        // 此处进行数据翻译操作，，根据不同的业务逻辑将entity对象转为vo对象......

        return vo;
    }

    @Override
    public SysUserEntity findEntity(Integer entityId) {
        SysUserEntity entity = super.getById(entityId);
        if (ObjectUtil.isEmpty(entity)) {
            throw new CommonServiceException("实体未找到（{}）", entityId);
        }
        return entity;
    }

    @Override
    public Page<SysUserVo> page(SysUserPageParam pageParam) {
        QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isAllNotEmpty(pageParam.getSortField(), pageParam.getSortType())) {
            queryWrapper.orderBy(true,
                    pageParam.getSortType() == CommonSortTypeEnum.ASC,
                    StrUtil.toUnderlineCase(pageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(SysUserEntity::getSortCode);
        }
        queryWrapper.lambda().orderByAsc(SysUserEntity::getId);

        Page<SysUserEntity> entityPage = super.page(pageParam.toBaomidouPage(), queryWrapper);
        // 此处进行远程调用或关联查询......

        Page<SysUserVo> voPage = CommonUtil.convertPage(entityPage, entity -> {
            SysUserVo vo = sysUserMapStruct.entityToVo(entity);
            // 此处进行数据翻译操作，根据不同的业务逻辑将entity对象转为vo对象......

            return vo;
        });
        return voPage;
    }

    @Override
    public SysUserEntity findByAccountKeyword(String keyword) {
        return findByAccountKeyword(keyword, keyword, keyword);
    }

    /**
     * 通过账号、邮箱或手机号查询用户
     *
     * @param account 账号
     * @param email   邮箱
     * @param phone   手机号
     * @return 如果存在用户则返回，如果不存在返回空
     */
    public SysUserEntity findByAccountKeyword(String account, String email, String phone) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getAccount, account)
                .or().eq(SysUserEntity::getEmail, email)
                .or().eq(SysUserEntity::getPhone, phone);
        return super.getOne(queryWrapper);
    }

    @Override
    public SysUserVo register(SysUserRegisterParam registerParam) {
        // 校验用户名、邮箱和手机号不能重复
        SysUserEntity existUser = findByAccountKeyword(
                registerParam.getAccount(), registerParam.getEmail(), registerParam.getPhone());
        if (ObjectUtil.isNotNull(existUser)) {
            throw new CommonServiceException("账号、邮箱或手机号已经被注册过了！");
        }

        SysUserEntity user = sysUserMapStruct.registerParamToEntity(registerParam);
        // 生成密码的hash值
        String hashPassword = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt(LOG_ROUNDS));
        user.setPassword(hashPassword);
        initUser(user);
        super.save(user);

        return sysUserMapStruct.entityToVo(user);
    }

    /**
     * 初始化用户
     *
     * @param user 用户
     */
    private void initUser(SysUserEntity user) {
        if (ObjectUtil.isNotNull(user.getGender())) {
            user.setGender(SysUserGenderEnum.SECRET);
        }
        // TODO 此处可能会处理用户密级
        user.setStatus(SysUserStatusEnum.NORMAL);
    }

    @Override
    public SysUserVo login(SysUserLoginParam loginParam) {
        // 根据账号、邮箱和手机号查询用户信息
        SysUserEntity user = findByAccountKeyword(loginParam.getAccount());
        if (ObjectUtil.isNull(user)) {
            throw new CommonServiceException("用户不存在");
        }

        // 验证用户密码是否正确
        if (!BCrypt.checkpw(loginParam.getPassword(), user.getPassword())) {
            throw new CommonServiceException("密码错误");
        }

        // sa-token登录操作
        StpUtil.login(user.getId());
        // 获取当前账号 id 的 Account-Session, 并决定在 Session 尚未创建时，新建并返回
        SaSession accountSession = StpUtil.getSession(true);
        // 获取当前用户的权限集合，并存入accountSession中
        accountSession.set("permission", sysPermissionService.listByLoginUser());

        // 最后需要将token放到vo对象中
        SysUserVo vo = sysUserMapStruct.entityToVo(user);
        vo.setToken(StpUtil.getTokenValue());

        return vo;
    }

    @Override
    public SysUserVo getLoginUser() {
        return detail(new SysUserIdParam(StpUtil.getLoginIdAsInt()));
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }
}